home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 12 / Cream of the Crop 12 (Part II) / Cream of the Crop 12 (Part II).iso / OS2 / LW32.ZIP / TAP11.ZIP / tapapp.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-10  |  20.4 KB  |  791 lines

  1. //
  2. // TAPAPP.C
  3. //
  4. // TAP
  5. // File Transfer Data Sharing
  6. // Application Code
  7. // Revision 1.10
  8. //
  9. // 12/28/94   First created
  10. //  4/24/95   Structures aligned with DWORDS
  11. //            Dynamic extension lists added
  12. //            Fixed EMERGENCY_CLOSE to use bitwise NOT (~)
  13. //
  14. #define INCL_DOSERRORS
  15. #define INCL_WINSHELLDATA
  16. #define INCL_DOS
  17.  
  18. #include <stdio.h>
  19. #include <stdlib.h>
  20. #include <process.h>
  21. #include <string.h>
  22. #include <os2.h>
  23. #include "tapapp.h"
  24.  
  25. //
  26. // PTAPAPPENTRY BuildTapAppEntry_TAP(char *szDescription,
  27. //                                  char *szProgram,
  28. //                                  char *szParams,
  29. //                                  PSZ pszExtension[],
  30. //                                  ULONG ulNumExtensions);
  31. //
  32. // This function allocates and builds a TAPAPPENTRY
  33. // that should be used to register a TAP application with
  34. // the TAP servers.
  35. //
  36. // Parameters
  37. // szDescription
  38. //   Description, up to 255 characters, of the application.
  39. // szProgram
  40. //   Fully qualified path to the TAP executable.
  41. // szParams
  42. //   Parameters to pass to the TAP program (max: 83 characters)
  43. // pszExtension
  44. //   A pointer to an array of pointers to strings, each
  45. //   string containing an file extension this application
  46. //   supports.
  47. // ulNumExtensions
  48. //   Number of extensions the application can handle.
  49. //   If this is zero, pszExtension may be NULL.
  50. //
  51. // Returns
  52. //   A pointer to a TAPAPPENTRY.
  53. //
  54. //   WARNING: The CALLER (that's you) is responsible for
  55. //            freeing this structure after using it.
  56. //            This can be done by calling the standard
  57. //            C function free.
  58. //
  59. PTAPAPPENTRY BuildTapAppEntry_TAP(char *szDescription,
  60.                                   char *szProgram,
  61.                                   char *szParams,
  62.                                   PSZ pszExtension[],
  63.                                   ULONG ulNumExtensions)
  64. {
  65. PTAPAPPENTRY pTapAppEntry;
  66. PEXTENSIONLIST pExtList;
  67. ULONG i, ulSize;
  68.  
  69.    // Compute the size of the TAPAPPENTRY structure with
  70.    // the extension list appended
  71.    for (i = 0, ulSize = sizeof(TAPAPPENTRY); i < ulNumExtensions; i++)
  72.       ulSize += sizeof(((PEXTENSIONLIST)NULL)->cb) +
  73.                    sizeof(((PEXTENSIONLIST)NULL)->szExtension) +
  74.                      strlen(pszExtension[i]);
  75.  
  76.    // Allocate a TAPAPPENTRY structure
  77.    pTapAppEntry = (PTAPAPPENTRY) malloc (ulSize);
  78.  
  79.    // Fill in the TAPAPPENTRY structure
  80.    pTapAppEntry->cb = ulSize;
  81.    strcpy(pTapAppEntry -> szDescription, szDescription);
  82.    strcpy(pTapAppEntry -> szProgram, szProgram);
  83.    strcpy(pTapAppEntry -> szParams, szParams);
  84.    pTapAppEntry->ulExtensions = ulNumExtensions;
  85.  
  86.    // Set pExtList to point to the memory location immediately
  87.    // following the TAPAPPENTRY structure
  88.    pExtList = (PEXTENSIONLIST) ((PBYTE)pTapAppEntry + sizeof(TAPAPPENTRY));
  89.  
  90.    // Fill the memory after TAPPAPPENTRY with variable size EXTENSIONLISTs
  91.    for (i = 0; i < ulNumExtensions; i++)
  92.    {
  93.       pExtList -> cb = sizeof(((PEXTENSIONLIST)NULL)->cb) +
  94.                           sizeof(((PEXTENSIONLIST)NULL)->szExtension) +
  95.                               strlen(pszExtension[i]);
  96.       strcpy(pExtList->szExtension, pszExtension[i]);
  97.  
  98.       // Go to the next EXTENSIONLIST structure
  99.       pExtList = (PEXTENSIONLIST) ((PBYTE)pExtList + pExtList -> cb);
  100.    }
  101.  
  102.    // Warning, the caller must free this up.
  103.    return pTapAppEntry;
  104. }
  105.  
  106. //
  107. // int RegisterApplication_TAP(char *szAppName,
  108. //                                         PTAPAPPENTRY pTapAppEntry);
  109. //
  110. // Registers a TAP Application so that TAP Servers can
  111. // find it. This need only be done once.
  112. //
  113. // Parameters:
  114. // szAppName
  115. //   Name of the TAP Application
  116. // pTapAppEntry
  117. //   A pointer to a structure containing
  118. //   information about this TAP application.
  119. //   See TAP.H for the members of this
  120. //   structure. The TAP application is
  121. //      responsible for filling this out
  122. //   completely and correctly.
  123. //
  124. // Returns: TRUE on success
  125. //
  126. int RegisterApplication_TAP(char *szAppName,
  127.                                      PTAPAPPENTRY pTapAppEntry)
  128. {
  129. int iRet = TRUE;
  130.  
  131.     // Write application data to the INI file
  132.     iRet =
  133.     (INT)PrfWriteProfileData(HINI_SYSTEMPROFILE,
  134.                                 TAP_INI_APPNAME,
  135.                                 szAppName,
  136.                                 (PVOID) pTapAppEntry,
  137.                                 pTapAppEntry -> cb);
  138.  
  139.     return iRet;
  140. }
  141.  
  142. //
  143. // int DeRegisterApplication_TAP(char *szAppName);
  144. //
  145. // Deregisters a TAP Application so that it is unavailable
  146. // to TAP Servers.
  147. //
  148. // Parameters:
  149. // szAppName
  150. //   Name of the TAP Application
  151. //
  152. // Returns: TRUE on success
  153. //
  154. int DeRegisterApplication_TAP(char *szAppName)
  155. {
  156. int iRet = TRUE;
  157.  
  158.     // Remove application from the INI file
  159.     iRet =
  160.     (INT)PrfWriteProfileData(HINI_SYSTEMPROFILE,
  161.                                 TAP_INI_APPNAME,
  162.                                 szAppName,
  163.                                 NULL,
  164.                                 0);
  165.  
  166.     return iRet;
  167. }
  168.  
  169. //
  170. // int OpenFile_TAP(PTAPAPPINFO pTapAppInfo, PHFILE phFile);
  171. //
  172. // Opens the current file being transferred for
  173. // shared reading.
  174. //
  175. // Parameters:
  176. // pTapAppInfo
  177. //  Pointer to the TAP application's instance data.
  178. // phFile
  179. //  Pointer to an OS/2 file handle. (output)
  180. //
  181. // Returns: TRUE on success
  182. //
  183. int OpenFile_TAP(PTAPAPPINFO pTapAppInfo, PHFILE phFile)
  184. {
  185. APIRET rc;
  186. ULONG ActionTaken;
  187. int iRet = TRUE;
  188.  
  189.     // Request exclusive access
  190.     DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  191.                                 (ULONG)SEM_INDEFINITE_WAIT);
  192.  
  193.     //
  194.     // Open an already existing file for read only access
  195.     //
  196.     // As a child process we really already have an
  197.     // inherited file handle but we're ignoring this fact
  198.     //
  199.     rc = DosOpen(pTapAppInfo -> tiCurrent . szFileName,
  200.                         &(pTapAppInfo -> hUserFile),
  201.                         &ActionTaken,
  202.                         0,
  203.                         FILE_NORMAL,
  204.                         OPEN_ACTION_FAIL_IF_NEW |
  205.                         OPEN_ACTION_OPEN_IF_EXISTS,
  206.                         OPEN_SHARE_DENYNONE |
  207.                         OPEN_ACCESS_READONLY,
  208.                         NULL);
  209.  
  210.     if (rc)
  211.         iRet = FALSE;
  212.     else
  213.         // Success, return file handle
  214.         *phFile = pTapAppInfo -> hUserFile;
  215.  
  216.     // Release exclusive access
  217.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  218.  
  219.     return iRet;
  220. }
  221.  
  222. //
  223. // int CloseFile_TAP(PTAPAPPINFO pTapAppInfo, HFILE hFile)
  224. //
  225. // Closes a the current file opened with OpenFile_TAP.
  226. //
  227. // Parameters:
  228. // pTapAppInfo
  229. //  Pointer to the TAP application's instance data.
  230. // hFile
  231. //  OS/2 handle to the file to be closed.
  232. //
  233. // Returns: TRUE on success
  234. //
  235. int CloseFile_TAP(PTAPAPPINFO pTapAppInfo, HFILE hFile)
  236. {
  237. int iRet = TRUE;
  238. APIRET rc;
  239.  
  240.     // Request exclusive access
  241.     DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  242.                                 (ULONG)SEM_INDEFINITE_WAIT);
  243.  
  244.     // Close file
  245.     rc = DosClose(hFile);
  246.  
  247.     if (rc)
  248.         iRet = FALSE;
  249.  
  250.     // Release exclusive access
  251.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  252.  
  253.     return iRet;
  254. }
  255.  
  256. //
  257. // PTAPAPPINFO InitializeApplication_TAP(int argc, char **argv);
  258. //
  259. // Initializes the TAP subsystem. This function must be called
  260. // as one of the first functions called in the TAP application.
  261. //
  262. // Parameters:
  263. // argc & argv - Standard command line parameters passed
  264. // to main on startup
  265. //
  266. // Returns: A pointer to the TAP instance data on success,
  267. // otherwise NULL. A NULL return value most likely means this
  268. // program was NOT started from a TAP server as required.
  269. //
  270. PTAPAPPINFO InitializeApplication_TAP(int argc, char **argv)
  271. {
  272. PTAPAPPINFO pTapAppInfo = NULL;
  273. int cnter;
  274. char szPipeName[CCHMAXPATH];
  275. HFILE PipeHandle;
  276. ULONG ActionTaken;
  277. APIRET rc;
  278.  
  279.     // Parse pipe name from the command line
  280.     for(cnter=0; cnter<argc; cnter++)
  281.         if (!strncmp(argv[cnter], "/TAP=", 5))
  282.             strcpy(szPipeName, (argv[cnter] + 5));
  283.  
  284.     // Open named pipe
  285.     rc = DosOpen(szPipeName,
  286.                       &PipeHandle,
  287.                       &ActionTaken,
  288.                       0L,
  289.                       FILE_NORMAL,
  290.                       FILE_OPEN,
  291.                       OPEN_ACCESS_READWRITE | OPEN_SHARE_DENYNONE,
  292.                       (PEAOP2) NULL);
  293.  
  294.     // Allocate memory
  295.     if (!rc)
  296.         pTapAppInfo = (PTAPAPPINFO) malloc(sizeof(TAPAPPINFO));
  297.  
  298.     if (pTapAppInfo)
  299.     {
  300.         // Initialize TAPAPPINFO structure
  301.         pTapAppInfo -> cb = sizeof(TAPAPPINFO);
  302.         pTapAppInfo -> lShutdown = FALSE;
  303.         pTapAppInfo -> hReadPipe = (HFILE) PipeHandle;
  304.  
  305.         // Create mutex semaphore
  306.         DosCreateMutexSem(NULL,
  307.                                 &(pTapAppInfo -> hAppMutex),
  308.                                 0,
  309.                                 FALSE);
  310.  
  311.         // Initialize version info
  312.  
  313.         pTapAppInfo -> szVersion[0] = '\0';
  314.         pTapAppInfo -> lVersionAvailable = FALSE;
  315.  
  316.         // Initialize TAPINFO structures
  317.         pTapAppInfo -> tiCurrent . szFileName [0] = '\0';
  318.         pTapAppInfo -> tiCurrent . lCurrentFileSize = TAP_SIZE_UNKNOWN;
  319.         pTapAppInfo -> tiCurrent . lCompleteFileSize = TAP_SIZE_UNKNOWN;
  320.         pTapAppInfo -> tiCurrent . ulFlags = 0;
  321.  
  322.         pTapAppInfo -> tiNext . szFileName [0] = '\0';
  323.         pTapAppInfo -> tiNext . lCurrentFileSize = TAP_SIZE_UNKNOWN;
  324.         pTapAppInfo -> tiNext . lCompleteFileSize = TAP_SIZE_UNKNOWN;
  325.         pTapAppInfo -> tiNext . ulFlags = 0;
  326.  
  327.         // Start TAP Application thread
  328.       #ifdef __BORLANDC__
  329.         _beginthread(ApplicationThread_TAP,
  330.                             8192,
  331.                             (void *) pTapAppInfo);
  332.       #else
  333.         _beginthread(ApplicationThread_TAP,
  334.                             NULL,
  335.                             8192,
  336.                             (void *) pTapAppInfo);
  337.       #endif
  338.     }
  339.  
  340.     return pTapAppInfo;
  341. }
  342.  
  343. //
  344. // int DeInitializeApplication_TAP(PTAPAPPINFO pTapAppInfo);
  345. //
  346. // Deinitializes the TAP subsystem.
  347. //
  348. // Parameters:
  349. // pTapAppInfo
  350. //  Pointer to the TAP application's instance data.
  351. //
  352. // Returns: TRUE on success
  353. //
  354. int DeInitializeApplication_TAP(PTAPAPPINFO pTapAppInfo)
  355. {
  356. int iRet = TRUE;
  357.  
  358.     // Request exclusive access
  359.     DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  360.                                 (ULONG)SEM_INDEFINITE_WAIT);
  361.  
  362.     // Tell the application thread we want to shut down
  363.     pTapAppInfo -> lShutdown = TRUE;
  364.  
  365.     // Release exclusive access
  366.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  367.  
  368.     return iRet;
  369. }
  370.  
  371. //
  372. // int NextFile_TAP(PTAPAPPINFO pTapAppInfo);
  373. //
  374. // Waits for the next file in the transfer session
  375. // or a cancel or an end of batch condition.
  376. //
  377. // Parameters:
  378. // pTapAppInfo
  379. //  Pointer to the TAP application's instance data.
  380. //
  381. // Returns: TRUE if another file transfer has started.
  382. // FALSE if a cancel or end of batch condition has
  383. // been encountered.
  384. //
  385. int NextFile_TAP(PTAPAPPINFO pTapAppInfo)
  386. {
  387. int iRet = TRUE;
  388. int ExitCondition = FALSE;
  389.  
  390.     do
  391.     {
  392.         // Request exclusive access
  393.         DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  394.                                     (ULONG)SEM_INDEFINITE_WAIT);
  395.  
  396.         // Check if the next packet begins a new file
  397.         ExitCondition = pTapAppInfo -> tiNext.ulFlags & TAP_BOF ? TRUE : FALSE;
  398.  
  399.         // Special condition: if the TAP applicationstarted at this middle
  400.         // of a file, we get no BOF (Begin of File) flag. To detect this
  401.         // condition we check if the current filename is the null string
  402.         // while the next filename is the non-empty string
  403.         if ( (pTapAppInfo -> tiCurrent.szFileName [0] == 0) &&
  404.               (pTapAppInfo -> tiNext.szFileName [0] != 0) )
  405.             ExitCondition = TRUE;
  406.  
  407.         // Check for exit conditions
  408.         if ( (pTapAppInfo -> tiNext.ulFlags & TAP_CANCEL) ||
  409.               (pTapAppInfo -> tiNext.ulFlags & TAP_EOB) )
  410.         {
  411.             iRet = FALSE;
  412.             ExitCondition = TRUE;
  413.         }
  414.  
  415.         // If we're going to exit, update the current data packet
  416.         if (ExitCondition)
  417.         {
  418.             pTapAppInfo -> tiCurrent = pTapAppInfo -> tiNext;
  419.             pTapAppInfo -> tiNext . ulFlags = 0;
  420.         }
  421.  
  422.         // Release exclusive access
  423.         DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  424.  
  425.         // Wait for 1/4 sec if this loop will repeat
  426.         if (!ExitCondition)
  427.             DosSleep(250);
  428.  
  429.     } while (!ExitCondition);
  430.  
  431.     return iRet;
  432. }
  433.  
  434.  
  435. //
  436. // int MoreData_TAP(PTAPAPPINFO pTapAppInfo);
  437. //
  438. // Waits for more data to arrive or one of
  439. // the following conditions to occur:
  440. // CANCEL, END OF BATCH, BEGIN NEW FILE, EOF
  441. //
  442. // Parameters:
  443. // pTapAppInfo
  444. //  Pointer to the TAP application's instance data.
  445. //
  446. // Returns: TRUE if more data has been received.
  447. // FALSE if any other condition has occured.
  448. //
  449. // If FALSE is returned there will be no more data
  450. // for the current file. Recommended action is to
  451. // check the file size and process any still
  452. // unprocessed data, then call NextFile_TAP
  453. // to determine if there are any more files to
  454. // process.
  455. //
  456. int MoreData_TAP(PTAPAPPINFO pTapAppInfo)
  457. {
  458. int iRet = TRUE;
  459. int ExitCondition = FALSE;
  460.  
  461.     do
  462.     {
  463.         // Request exclusive access
  464.         DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  465.                                     (ULONG)SEM_INDEFINITE_WAIT);
  466.  
  467.         // Check for exit conditions that pertain to
  468.         // batch conditions (End of batch, cancel)
  469.         // that should be handled by NextFile
  470.         if ( (pTapAppInfo -> tiNext.ulFlags & TAP_CANCEL) ||
  471.               (pTapAppInfo -> tiNext.ulFlags & TAP_EOB)    ||
  472.               (pTapAppInfo -> tiNext.ulFlags & TAP_BOF) )
  473.         {
  474.             iRet = FALSE;
  475.             ExitCondition = TRUE;
  476.         }
  477.          else
  478.         // Check for exit conditions we need
  479.         // to handle here (pertain to the file)
  480.         if (pTapAppInfo -> tiNext.ulFlags & TAP_EOF)
  481.         {
  482.             iRet = FALSE;
  483.             ExitCondition = TRUE;
  484.             pTapAppInfo -> tiNext . ulFlags = 0;
  485.         }
  486.          else
  487.         // Check if the next packet has new data
  488.         if (pTapAppInfo -> tiNext.ulFlags & TAP_NEW_SIZE)
  489.         {
  490.             ExitCondition = TRUE;
  491.             pTapAppInfo -> tiNext . ulFlags = 0;
  492.         }
  493.  
  494.         if (ExitCondition)
  495.             pTapAppInfo -> tiCurrent = pTapAppInfo -> tiNext;
  496.  
  497.         // Release exclusive access
  498.         DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  499.  
  500.         // Wait for 1/4 sec if this loop will repeat
  501.         if (!ExitCondition)
  502.             DosSleep(250);
  503.  
  504.     } while (!ExitCondition);
  505.  
  506.     return iRet;
  507. }
  508.  
  509. //
  510. // long QueryStatus_TAP(PTAPAPPINFO pTapAppInfo);
  511. //
  512. // Queries the status of the current file.
  513. // This really isn't very useful.
  514. //
  515. // Parameters:
  516. // pTapAppInfo
  517. //  Pointer to the TAP application's instance data.
  518. //
  519. // Returns: Bitmapped flags
  520. //
  521. long QueryStatus_TAP(PTAPAPPINFO pTapAppInfo)
  522. {
  523. long lRet = 0;
  524.  
  525.     // Request exclusive access
  526.     DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  527.                                 (ULONG)SEM_INDEFINITE_WAIT);
  528.  
  529.     // Return current TAP flags
  530.     lRet = (LONG)(pTapAppInfo -> tiCurrent . ulFlags);
  531.  
  532.     // Release exclusive access
  533.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  534.  
  535.     return lRet;
  536. }
  537.  
  538. //
  539. // int QueryServerVersion_TAP(PTAPAPPINFO pTapAppInfo,
  540. //                                    char *szVersion);
  541. //
  542. // Queries the server version string. This function
  543. // returns a valid server version string only when it
  544. // has received at least one packet of information
  545. // over the named pipe. It's therefore recommended
  546. // that this not be used until the first call to
  547. // NextFile_TAP returns.
  548. //
  549. // Parameters:
  550. // pTapAppInfo
  551. //  Pointer to the TAP application's instance data.
  552. // szVersion
  553. //  Pointer to a memory location of at least 31 bytes
  554. //  to hold the server version string (output)
  555. //
  556. // Returns: TRUE on success
  557. //
  558. int QueryServerVersion_TAP(PTAPAPPINFO pTapAppInfo,
  559.                                     char *szVersion,
  560.                                     ULONG ulBufLen)
  561. {
  562. int iRet = TRUE;
  563.     ULONG ulRetries = 10; // Max 10 retries = 2.5 sec
  564.  
  565.     for (;;) {
  566.  
  567.         // Request exclusive access
  568.         DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  569.                                 (ULONG)SEM_INDEFINITE_WAIT);
  570.  
  571.         if (pTapAppInfo -> lVersionAvailable)
  572.             break;
  573.  
  574.         DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  575.  
  576.         if (ulRetries-- == 0)    
  577.             return (FALSE);
  578.  
  579.         DosSleep (250);
  580.         }
  581.  
  582.     // Make a copy of the server version string
  583.     strncpy (szVersion, pTapAppInfo -> szVersion, ulBufLen - 1);
  584.     szVersion[ulBufLen - 1] = '\0';
  585.  
  586.     // Release exclusive access
  587.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  588.  
  589.     return iRet;
  590. }
  591.  
  592. //
  593. // int QueryFileName_TAP(PTAPAPPINFO pTapAppInfo,
  594. //                                    char *szFileName);
  595. //
  596. // Parameters:
  597. // pTapAppInfo
  598. //  Pointer to the TAP application's instance data.
  599. // szFileName
  600. //  Pointer to a memory block of CCHMAXPATH length
  601. //  where the current fully qualified path and file name
  602. //  is copied. (output)
  603. //
  604. // Returns: TRUE on success;
  605. //
  606. int QueryFileName_TAP(PTAPAPPINFO pTapAppInfo,
  607.                                 char *szFileName)
  608. {
  609. int iRet = TRUE;
  610.  
  611.     // Request exclusive access
  612.     DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  613.                                 (ULONG)SEM_INDEFINITE_WAIT);
  614.  
  615.     // Make a copy of the fully qualified file name
  616.     strcpy(szFileName, pTapAppInfo -> tiCurrent . szFileName);
  617.  
  618.     // Release exclusive access
  619.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  620.  
  621.     return iRet;
  622. }
  623.  
  624. //
  625. // long QueryCompleteSize_TAP((PTAPAPPINFO pTapAppInfo);
  626. //
  627. // Parameters:
  628. // pTapAppInfo
  629. //  Pointer to the TAP application's instance data.
  630. //
  631. // Returns: The size of the complete file or -1 (TAP_SIZE_UNKNOWN)
  632. // if that size is unknown.
  633. //
  634. long QueryCompleteSize_TAP(PTAPAPPINFO pTapAppInfo)
  635. {
  636. long lRet = TRUE;
  637.  
  638.     // Request exclusive access
  639.     DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  640.                                 (ULONG)SEM_INDEFINITE_WAIT);
  641.  
  642.     // Return complete size
  643.     lRet = pTapAppInfo -> tiCurrent . lCompleteFileSize;
  644.  
  645.     // Release exclusive access
  646.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  647.  
  648.     return lRet;
  649. }
  650.  
  651. //
  652. // long QueryCurrentSize_TAP((PTAPAPPINFO pTapAppInfo);
  653. //
  654. // Parameters:
  655. // pTapAppInfo
  656. //  Pointer to the TAP application's instance data.
  657. //
  658. // Returns: The size of the current file or -1 (TAP_SIZE_UNKNOWN)
  659. // if that size is unknown.
  660. //
  661. long QueryCurrentSize_TAP(PTAPAPPINFO pTapAppInfo)
  662. {
  663. long lRet = TRUE;
  664.  
  665.     // Request exclusive access
  666.     DosRequestMutexSem(pTapAppInfo -> hAppMutex,
  667.                                 (ULONG)SEM_INDEFINITE_WAIT);
  668.  
  669.     // Return current size
  670.     lRet = pTapAppInfo -> tiCurrent . lCurrentFileSize;
  671.  
  672.     // Release exclusive access
  673.     DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  674.  
  675.     return lRet;
  676. }
  677.  
  678. //
  679. // void ApplicationThread_TAP(void *AppInfo)
  680. //
  681. // -= NOT to be called by any other module =-
  682. //
  683. // This is a thread function which serves
  684. // the purpose of servicing the queue and
  685. // updating data structures accordingly.
  686. //
  687. // This function also handles emergency file
  688. // closes.
  689. //
  690. void ApplicationThread_TAP (void *AppInfo) {
  691.     PTAPAPPINFO pTapAppInfo = (PTAPAPPINFO)AppInfo;
  692.  
  693.     while (!pTapAppInfo->lShutdown) {
  694.         USHORT      usPacketSize = 0;    
  695.         ULONG       ulBytesRead;
  696.         PTAPPACKET pTapPacket;
  697.  
  698.         for (;;) {
  699.             AVAILDATA availData;
  700.             ULONG     ulState;
  701.  
  702.             DosPeekNPipe (pTapAppInfo->hReadPipe, &usPacketSize, sizeof (usPacketSize), &ulBytesRead, &availData, &ulState);
  703.  
  704.             // Have we got the whole packet yet ?
  705.  
  706.             if ((ulBytesRead == sizeof (usPacketSize)) && (availData.cbpipe >= usPacketSize))
  707.                 break;
  708.  
  709.             // Shutdown on request or if pipe is no longer connected
  710.  
  711.             if ((pTapAppInfo->lShutdown) || (ulState != NP_STATE_CONNECTED))
  712.                 goto _ShutDown;
  713.  
  714.             // Not enough data yet, sleep for 1/4 second
  715.  
  716.             DosSleep (250);
  717.             }
  718.  
  719.         // Read packet
  720.  
  721.         pTapPacket = (PTAPPACKET)malloc (usPacketSize);
  722.  
  723.         DosRead(pTapAppInfo->hReadPipe, pTapPacket, usPacketSize, &ulBytesRead);
  724.  
  725.         if (ulBytesRead == usPacketSize) {
  726.             ULONG ulFlags = pTapPacket->flagPacket.usFlags;
  727.  
  728.             if (ulFlags & TAP_EMERGENCY_CLOSE) {
  729.                 // Close up file ASAP
  730.                 DosClose (pTapAppInfo -> hUserFile);
  731.                 // Reset emergency flag, it has been handled
  732.                 ulFlags &= ~(ULONG)TAP_EMERGENCY_CLOSE;
  733.                 }
  734.  
  735.             // Request exclusive access
  736.             DosRequestMutexSem (pTapAppInfo->hAppMutex, (ULONG)SEM_INDEFINITE_WAIT);
  737.  
  738.             if (ulFlags & TAP_VERSION) {
  739.                 LONG lLen = min (sizeof (pTapAppInfo->szVersion) - 1, pTapPacket->versionPacket.usVersionLength);
  740.                 strncpy (pTapAppInfo->szVersion, pTapPacket->versionPacket.szVersion, (UINT)lLen);
  741.                 pTapAppInfo->szVersion[lLen] = '\0';
  742.                 pTapAppInfo -> lVersionAvailable = TRUE;
  743.                 }
  744.             else if (ulFlags & TAP_BOF) {
  745.                 LONG lLen;
  746.                 pTapAppInfo->tiNext.lCurrentFileSize = pTapPacket->beginFilePacket.lCurrentFileSize;
  747.                 pTapAppInfo->tiNext.lCompleteFileSize = pTapPacket->beginFilePacket.lCompleteFileSize;
  748.                 lLen = min (sizeof (pTapAppInfo->tiNext.szFileName) - 1, pTapPacket->beginFilePacket.usFileNameLength);
  749.                 strncpy (pTapAppInfo->tiNext.szFileName, pTapPacket->beginFilePacket.szFileName, (UINT)lLen);
  750.                 pTapAppInfo->tiNext.szFileName[lLen] = '\0';
  751.                 }
  752.             else if (ulFlags & TAP_NEW_SIZE) {
  753.                 pTapAppInfo->tiNext.lCurrentFileSize = pTapPacket->newSizePacket.lCurrentFileSize;
  754.                 pTapAppInfo->tiNext.lCompleteFileSize = pTapPacket->newSizePacket.lCompleteFileSize;
  755.                 }
  756.  
  757.             // Acknowledge server if requested
  758.             if (ulFlags & TAP_ACKNOWLEDGE) {
  759.                 ULONG ulBytesWritten;
  760.                 pTapPacket->flagPacket.cb = sizeof (pTapPacket->flagPacket);
  761.                 pTapPacket->flagPacket.usFlags = TAP_ACKNOWLEDGE;
  762.                 DosWrite (pTapAppInfo->hReadPipe, pTapPacket, pTapPacket->flagPacket.cb, &ulBytesWritten);
  763.                 }
  764.  
  765.             pTapAppInfo->tiNext.ulFlags |= ulFlags;
  766.  
  767.             // Release exclusive access
  768.             DosReleaseMutexSem(pTapAppInfo -> hAppMutex);
  769.  
  770.             }
  771.  
  772.         free (pTapPacket);
  773.         }
  774.  
  775. _ShutDown:
  776.  
  777.     // ***
  778.     // Shutdown
  779.     // ***
  780.  
  781.     // Free mutex
  782.     DosCloseMutexSem(pTapAppInfo -> hAppMutex);
  783.  
  784.     // Shut down pipe
  785.     DosClose(pTapAppInfo -> hReadPipe);
  786.  
  787.     // Free memory
  788.     free (pTapAppInfo);
  789. }
  790.  
  791.